﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;


namespace StarTrekFileBrowser
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        #region variables

        //we start at on the hard drive
        public static string STARTFOLDER = "C:\\";
        private List<string> knownEndingsForImages = new List<string>() { "bmp", "png", "jpg", "jpeg", "gif" };
        private List<string> knownEndingsForText = new List<string>() { "txt", "log", "xml", "html", "htm", "php" };


        public string CurrentPath
        {
            get { return (string)GetValue(CurrentPathProperty); }
            set { SetValue(CurrentPathProperty, value); }
        }
        public static readonly DependencyProperty CurrentPathProperty =
            DependencyProperty.Register("CurrentPath", typeof(string), typeof(MainWindow), new UIPropertyMetadata(STARTFOLDER));

        public Brush LeftSideColor
        {
            get { return (Brush)GetValue(LeftSideColorProperty); }
            set { SetValue(LeftSideColorProperty, value); }
        }
        public static readonly DependencyProperty LeftSideColorProperty =
            DependencyProperty.Register("LeftSideColor", typeof(Brush), typeof(MainWindow), new UIPropertyMetadata(Brushes.LightSkyBlue));

        private BrowserFileControl lastSelection = null;
        private FileDataTree Tree { get; set; }

        private List<FileDataTreeNode> knownNodes;

        private int leftListLayer = 1;
        private int middleListLayer = 2;
        private Dictionary<int, BrowserFileControl> activeOnLayer = new Dictionary<int, BrowserFileControl>();
        #endregion

        #region constructors
        public MainWindow()
        {
            knownNodes = new List<FileDataTreeNode>();

            InitializeComponent();

            Tree = new FileDataTree() { Path = CurrentPath };

            FileDataTreeNode root = new FileDataTreeNode(Tree)
            {
                FullFilename = Tree.Path,
                NodeType = NodeType.ROOT
            };

            var directories = Directory.GetDirectories(CurrentPath);
            var files = Directory.GetFiles(CurrentPath);

            FileDataTreeNode n = null;

            foreach (var d in directories)
            {
                n = new FileDataTreeNode(root)
                {
                    FullFilename = d,
                    NodeType = NodeType.FOLDER,
                    Aktive = false,
                    ChildrenChecked = false,
                    Image = null
                };
                knownNodes.Add(n);
            }

          

            foreach (var f in files)
            {
          
                n = new FileDataTreeNode(root)
                {
                    FullFilename = f,
                    NodeType = NodeType.FILE,
                    Aktive = false,
                    ChildrenChecked = true
                };
                knownNodes.Add(n);
            }


            items1.ItemsSource = Tree.Root.Children;
            items2.ItemsSource = new List<FileDataTreeNode>();
        }
        #endregion


        #region selection handling using mouse
        private void BrowserFileControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            BrowserFileControl uiele = sender as BrowserFileControl;

            doSelection(uiele);
        }

        private void BrowserFileControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            lastSelection = sender as BrowserFileControl;
            mouseDownPoint = e.GetPosition(TheWindow);
        }

        #endregion

        private void doSelection(BrowserFileControl uiele)
        {
            //only if down + up event are on the same uielement
            if (uiele == lastSelection)
            {
                //selecting the node on which was klickt
                var node = (from t in knownNodes where t.ID == uiele.NodeID && t.Layer == uiele.Layer select t).First();

                BrowserFileControl oldUiele = null;
                if (activeOnLayer.Keys.Contains(uiele.Layer)) oldUiele = activeOnLayer[uiele.Layer];

                //if it is not active
                if (!node.Aktive)
                {

                    if (activeOnLayer.Keys.Contains(uiele.Layer))
                    {
                        var oldUiEle = activeOnLayer[uiele.Layer];
                        var thaNode = (from t in knownNodes where t.ID == oldUiEle.NodeID select t).First();
                        thaNode.Aktive = false;
                        oldUiEle.ButtonRec.Fill = thaNode.FillColor;
                        oldUiEle.ButtonRec.Stroke = thaNode.StrokeColor;
                        oldUiEle.LineRec.Fill = thaNode.StrokeColor;
                    }

                    var aktiveUi = (from t in activeOnLayer.Keys where t >= uiele.Layer select activeOnLayer[t]).ToList();
                    foreach (var u in aktiveUi)
                    {
                        var n = (from t in knownNodes where t.ID == u.NodeID select t).First();
                        n.Aktive = false;
                        u.ButtonRec.Fill = n.FillColor;
                        u.ButtonRec.Stroke = n.StrokeColor;
                        u.LineRec.Fill = n.StrokeColor;

                        activeOnLayer.Remove(u.Layer);
                    }

                    //setting active and updating colors for the active node AND the ui element
                    node.Aktive = true;
                    uiele.ButtonRec.Fill = node.FillColor;
                    uiele.ButtonRec.Stroke = node.StrokeColor;
                    uiele.LineRec.Fill = node.StrokeColor;

                    //setting the active uielement in the dictionary
                    activeOnLayer[uiele.Layer] = uiele;

                    //if left list was clickt we set the right list to the node children list
                    if (uiele.Layer == leftListLayer)
                    {
                        //if the node is a folder
                        if (node.NodeType == NodeType.FOLDER)
                        {
                            //looking in the folder
                            checkSubFolderContent(node);
                            //middle list source is set to the children list
                            items2.ItemsSource = node.Children;
                            //changing the layer indices we need for some computations
                            leftListLayer = node.Layer;
                            middleListLayer = node.Layer + 1;

                            //content information unneeded
                            ContentInformation.Visibility = Visibility.Hidden;
                            //updating the path in the top
                            actualPathLabel.Content = node.FullFilename;

                            items1.ItemsSource = new List<FileDataTreeNode>();

                            //resetting the itemsource to the parent of the selected list
                            items1.ItemsSource = node.Parent.Children;

                            //uiele.LineRec.Fill = node.StrokeColor;

                        }
                        //else we have a file
                        else
                        {

                            if (oldUiele != null)
                            {
                                var oldNode = (from t in knownNodes where oldUiele.NodeID == t.ID select t).First();
                                oldNode.Aktive = false;
                                oldUiele.ButtonRec.Stroke = oldNode.StrokeColor;
                                oldUiele.ButtonRec.Fill = oldNode.FillColor;
                                oldUiele.LineRec.Fill = oldNode.StrokeColor;
                            }

                            //right side is empty
                            items2.ItemsSource = new List<FileDataTreeNode>();
                            //middleListLayer = -1;

                            //doing some file selection
                            fileSelected(node, uiele);
                            //OnFileSelected(sender, new OnFileSelectedEventArgs(node));
                            items1.ItemsSource = new List<FileDataTreeNode>();

                            //also resetting the itemsource - just in case
                            items1.ItemsSource = node.Parent.Children;

                        }

                        //calculating the length for the line on the right side
                        double newH = (node.ChildCount - 1) * 58;
                        if (node.ChildCount == 1) newH = 4;
                        connectLineCanvas.Height = (newH < 0 ? 0 : newH);
                    }
                    //if right list was selected
                    else if (uiele.Layer == middleListLayer)
                    {
                        //if node is a folder type
                        if (node.NodeType == NodeType.FOLDER)
                        {
                            //searching for content in the folder
                            checkSubFolderContent(node);
                            //setting itemsources
                            items1.ItemsSource = node.Parent.Children;
                            items2.ItemsSource = node.Children;
                            //changing the layers
                            leftListLayer = node.Layer;
                            middleListLayer = node.Layer + 1;

                            //activating the node we clickt on bevor it switched to the right
                            node.Aktive = true;
                            activeOnLayer[leftListLayer].ButtonRec.Stroke = node.StrokeColor;
                            activeOnLayer[leftListLayer].ButtonRec.Fill = node.FillColor;
                            activeOnLayer[leftListLayer].LineRec.Fill = node.LineColor;
                            //if list layer indice is bigger than 1 we show a small line in front
                            if (leftListLayer > 1) activeOnLayer[leftListLayer].FrontLineRec.Fill = node.FrontLineColor;

                            //resetting the line on the middle
                            connectLineCanvas.Height = 0.0;
                            if (node.ChildCount == 1) connectLineCanvas.Height = 4.0;

                            //hiding information for the content
                            ContentInformation.Visibility = Visibility.Hidden;

                            //updating the path in the top
                            actualPathLabel.Content = node.FullFilename;

                            //if (node.ChildCount > 0) activeOnLayer[leftListLayer].LineRec.Fill = Brushes.Yellow;
                        }
                        else
                        {
                            //else simply showing content information
                            fileSelected(node, uiele);
                            //OnFileSelected(sender, new OnFileSelectedEventArgs(node));
                        }

                        //calculating the length for the line on the right side
                        double newH = (items2.Items.Count - 1) * 58;
                        if (items2.Items.Count == 1) newH = 4;
                        connectLineCanvas.Height = (newH < 0 ? 0 : newH);

                    }

                }

            }
            else
            {
                //empty
            }
        }



        private void fileSelected(FileDataTreeNode node, BrowserFileControl bfc)
        {
            ContentInformation.Visibility = Visibility.Visible;
            ContentInformation.InformationText = "\n" + node.Filename + "." + node.FileEnding + "\n\n";

            var finfo = new FileInfo(node.FullFilename);

            ContentInformation.InformationText += "attribute list: " + finfo.Attributes + "\ncreated at: " + finfo.CreationTime + "\nlast access: " + finfo.LastAccessTime
                    + "\n\nsize: " + finfo.Length/1024 + " kbyte";

            ContentInformation.InformationText += "\n\nFull path: " + finfo.DirectoryName;

            //resetting the informaiton

            ContentInformation.ContentTextBlock.Visibility = Visibility.Hidden;
            ContentInformation.ContentTextBlock.Text = "";

            if (ContentInformation.ContentViewBox.Child != null)
            {
                ContentInformation.ContentViewBox.Child = null;
            }

            

            //if it is an image we can show it
            if (knownEndingsForImages.Contains(node.FileEnding))
            {
                Image img = new Image();
                img.Source = new BitmapImage(new Uri(node.FullFilename));
                ContentInformation.ContentViewBox.Child = img;
            }

            //if it is a txt file we want to display the content
            if (knownEndingsForText.Contains(node.FileEnding))
            {
                string cont = File.ReadAllText(node.FullFilename);
                ContentInformation.ContentTextBlock.Text = cont;
                ContentInformation.ContentTextBlock.Visibility = Visibility.Visible;
            }


        }


        #region subfolder checking + node creation
        private bool checkSubFolderContent(FileDataTreeNode parent)
        {
            if (parent.ChildrenChecked) return false;
            if (parent.NodeType == NodeType.FILE) return false;

            var dirs = Directory.GetDirectories(parent.FullFilename);
            var files = Directory.GetFiles(parent.FullFilename);

            FileDataTreeNode n = null;
            foreach (var d in dirs)
            {
                n = new FileDataTreeNode(parent)
                {
                    FullFilename = d,
                    NodeType = NodeType.FOLDER,
                    Aktive = false,
                    ChildrenChecked = false,
                    Image = null
                };
                knownNodes.Add(n);
            }

            foreach (var f in files)
            {
                n = new FileDataTreeNode(parent)
                {
                    FullFilename = f,
                    NodeType = NodeType.FILE,
                    Aktive = false,
                    ChildrenChecked = true
                };
                knownNodes.Add(n);
            }
            parent.ChildrenChecked = true;
            return true;
            
        }

        #endregion


        #region scroll handling

        private Point mouseDownPoint;
        private int mouseDownLayer = 0;


        private void items2ScrollView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            mouseDownPoint = e.GetPosition(TheWindow);
            mouseDownLayer = middleListLayer;
        }

        private void items1ScrollView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            mouseDownPoint = e.GetPosition(TheWindow);
            mouseDownLayer = leftListLayer;
        }

       
        private void items1ScrollView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //handling the scrolling
            Point mouseUpPoint = e.GetPosition(TheWindow);

            doScrollViewer1Actions(sender as ScrollViewer, mouseUpPoint, mouseDownPoint);
        }
        

        private void items2ScrollView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //handling the scrolling
            Point mouseUpPoint = e.GetPosition(TheWindow);
            doScrollViewer2Actions(sender as ScrollViewer, mouseUpPoint, mouseDownPoint);

        }

        #endregion

        private void doScrollViewer2Actions(ScrollViewer uiele, Point mouseUpP, Point mouseDownP)
        {


            if (mouseDownP.Y != mouseUpP.Y)
            {
                items2ScrollView.ScrollToVerticalOffset(items2ScrollView.VerticalOffset + (mouseUpP.Y - mouseDownP.Y));
            }

            //if dragged from left to right....
            //and the left layer index is bigger that 1
            if ((mouseDownLayer != 0) && (mouseDownLayer != middleListLayer) && (leftListLayer > 1))
            {
                //selecting the node from the layer before
                var lUiEle = activeOnLayer[leftListLayer - 1];
                var lNode = (from t in knownNodes where t.ID == lUiEle.NodeID select t).First();

                //the active node
                //var rUiEle = activeOnLayer[leftListLayer];
                //var rNode = (from t in knownNodes where t.ID == rUiEle.NodeID select t).First();
                //items2.ItemsSource = items1.Items;
                items1.ItemsSource = lNode.Parent.Children;
                items2.ItemsSource = lNode.Children;
                //items2.ItemsSource = rNode.Children;

                leftListLayer--;
                middleListLayer--;

                double newH = (items2.Items.Count - 1) * 58;
                if (items2.Items.Count == 1) newH = 4;
                connectLineCanvas.Height = (newH < 0 ? 0 : newH);

            }

        }


        private void doScrollViewer1Actions(ScrollViewer uiele, Point mouseUpP, Point mouseDownP)
        {

            if (mouseDownP.Y != mouseUpP.Y)
            {
                items1ScrollView.ScrollToVerticalOffset(items1ScrollView.VerticalOffset + (mouseUpP.Y - mouseDownP.Y));

            }

            //if a mouse layer was set (not the default value)
            //and the down layer is not left layer (its the middle)
            //and the left layer is in the activeonlayer list
            if ((mouseDownLayer != 0) && (mouseDownLayer != leftListLayer) && (activeOnLayer.Keys.Contains(leftListLayer)))
            {
                //select node which represents the left list
                var nodeL = (from t in knownNodes where t.ID == activeOnLayer[leftListLayer].NodeID select t).First();
                //only if the node has childs, else we do not want to move it
                if (nodeL.ChildCount > 0)
                {
                    //changing the itemsource
                    items1.ItemsSource = nodeL.Children;
                    //if already an item on a higher exists that was selected, we use it there
                    if (activeOnLayer.Keys.Contains(middleListLayer))
                    {
                        //selecting that node and set the itemsource
                        var nodeM = (from t in knownNodes where t.ID == activeOnLayer[middleListLayer].NodeID select t).First();
                        items2.ItemsSource = nodeM.Children;
                    }
                    else
                    {
                        //else it is empty
                        items2.ItemsSource = new List<FileDataTreeNode>();
                    }
                    //updating the counter
                    leftListLayer++;
                    middleListLayer++;

                    double newH = (items2.Items.Count - 1) * 58;
                    if (items2.Items.Count == 1) newH = 4;
                    connectLineCanvas.Height = (newH < 0 ? 0 : newH);

                }
            }

        }



        #region touchevents selection

        private TouchPoint touchDownPoint;
        private int touchDownLayer = 0;

        private void BrowserFileControl_TouchDown(object sender, TouchEventArgs e)
        {
            lastSelection = sender as BrowserFileControl;
            touchDownPoint = e.GetTouchPoint(TheWindow);
        }

        private void BrowserFileControl_TouchUp(object sender, TouchEventArgs e)
        {
            if (touchDownPoint.TouchDevice.Id == e.GetTouchPoint(TheWindow).TouchDevice.Id)
            {
                doSelection(sender as BrowserFileControl);
            }
        }

        #endregion

        #region touchevents scrollviewer
        private void items1ScrollView_TouchDown(object sender, TouchEventArgs e)
        {
            touchDownPoint = e.GetTouchPoint(TheWindow);
            touchDownLayer = leftListLayer;
        }

        private void items1ScrollView_TouchDup(object sender, TouchEventArgs e)
        {
            TouchPoint p = e.GetTouchPoint(TheWindow);
            if (p.TouchDevice.Id == touchDownPoint.TouchDevice.Id)
            {
                Point pDown = new Point(p.Position.X, p.Position.Y);
                Point pUp = new Point(touchDownPoint.Position.X, touchDownPoint.Position.Y);
                doScrollViewer1Actions(sender as ScrollViewer, pDown, pUp);
            }

        }

        private void items2ScrollView_TouchDown(object sender, TouchEventArgs e)
        {
            touchDownPoint = e.GetTouchPoint(TheWindow);
            touchDownLayer = middleListLayer;
        }

        private void items2ScrollView_TouchUp(object sender, TouchEventArgs e)
        {
            TouchPoint p = e.GetTouchPoint(TheWindow);
            if (p.TouchDevice.Id == touchDownPoint.TouchDevice.Id)
            {
                Point pDown = new Point(p.Position.X, p.Position.Y);
                Point pUp = new Point(touchDownPoint.Position.X, touchDownPoint.Position.Y);
                doScrollViewer2Actions(sender as ScrollViewer, pDown, pUp);
            }
        }
        #endregion

    }

    public class OnFileSelectedEventArgs : EventArgs
    {
        public FileDataTreeNode Node { get; set; }
        public OnFileSelectedEventArgs(FileDataTreeNode n)
        {
            Node = n;
        }
    }



}
        